#!/bin/bash

# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv)
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
# Copyright (C) 2018-present Team CoreELEC (https://coreelec.org)

. config/options ""

# usage
usage() {
  cat - >&2 <<EOUSAGE
SYNOPSIS
       ./script/create_addon [OPTION] [addons]...

DESCRIPTION
       create_addon builds one or more addons.

       --show-only
              output the list of packages, which are intented to build

       --write-logs=[yes,no,errors]
              write a log file per addon
              yes    - write for every addon a log (and keep it)
              no     - write no logs (default)
              errors - only keep logs for failed addons

       --log-path
              path where the logs are written
              default: \$BUILD/logs

       --help shows this message

       [addons]
              list of addons to build.
              The addons can identified by:
              - the name of the addon
              - a group name of addons
                  * all - all addons found under packages and project/*/packages
                  * official - all addons found under packages/addons
                  * binary - all addons found under packages/mediacenter/kodi-binary-addons
              - a regex term (grep styled), the term is automatic sorounded with string begin and end (^[term]$)

              addons can removed from list with a leading minus.

EXAMPLE
       build all addons
       > ./script/create_addon all

       build audio encoders and decoders, only
       > ./script/create_addon audioencoder.* audiodecoder.*

       build all, but not binary
       > ./script/create_addon all -binary

EOUSAGE
  exit ${1:0}
}

# functions
function find_addons() {
  local _paths=""
  local _filter="."
  case $1 in
    binary)      _paths="$ROOT/packages/mediacenter/kodi-binary-addons";;
    official)    _paths="$ROOT/packages/addons";;
    all)         _paths="$ROOT/packages $ROOT/projects/*/packages";;
    *)           _paths="$ROOT/packages $ROOT/projects/*/packages";
                 _filter="^$1$";;
  esac

  local _addons=$(
    find $_paths -name 'package.mk' \
      `# select packages with PKG_IS_ADDON (can yes, no or unset at this moment)` \
      | xargs grep -l 'PKG_IS_ADDON' \
      `# extract package name from path` \
      | sed 's|^.*/\([^/]*\)/package.mk$|\1|g' \
      `# filter package list against the given filter` \
      | grep -e "$_filter" \
      `# make entries unique` \
      | sort -u \
      `# select packages with PKG_IS_ADDON=yes (slow, but is a short list, now)` \
      | xargs -n1 -I{} /bin/bash -c '. ./config/options {} &>/dev/null; [ "$PKG_IS_ADDON" = "yes" ] && echo $PKG_NAME'
  )

  # check if anything is found
  local _count=$(wc -w <<< $_addons)
  if [ $_count -eq 0 ]; then
    # handle embedded addons here. Should only build when they are explictly specified in the addon list
    ( . ./config/options "$1" &>/dev/null
      [ "$PKG_IS_ADDON" != "embedded" -a "$PKG_IS_ADDON" != "yes" ] && exit 1
      echo $PKG_NAME
    )

    # abort when nothing found and not embedded
    if [ $? -ne 0 ]; then
      echo  "$(print_color CLR_ERROR "ERROR: '$1' matches nothing...")" >&$SILENT_OUT
      echo  "for more informations type: ./scripts/create_addon --help" >&$SILENT_OUT
      die
    fi
  fi

  echo $_addons
}

pack_addon() {
  scripts/install_addon $PKG_NAME $PKG_ADDON_ID || exit

  if [ "$2" != "-test" ] ; then
    ADDON_INSTALL_DIR="$TARGET_IMG/$ADDONS/$ADDON_VERSION/$PROJECT/$TARGET_ARCH/$PKG_ADDON_ID"
    ADDONVER="$(xmlstarlet sel -t -v "/addon/@version" $ADDON_BUILD/$PKG_ADDON_ID/addon.xml)"

    if [ -f $ADDON_INSTALL_DIR/$PKG_ADDON_ID-$ADDONVER.zip ]; then
      if [ "$ADDON_OVERWRITE" = "yes" ]; then
        rm $ADDON_INSTALL_DIR/$PKG_ADDON_ID-$ADDONVER.zip
      else
        build_msg "CLR_WARNING" "*** WARNING: ${PKG_ADDON_ID}-${ADDONVER}.zip already exists. Not overwrittng it. ***"
        return 0
      fi
    fi
    cd $ADDON_BUILD
    build_msg "CLR_INFO" "*** compressing addon ${PKG_ADDON_ID} ... ***"
    $TOOLCHAIN/bin/7za a -l -mx9 -bsp0 -bso0 -tzip $PKG_ADDON_ID-$ADDONVER.zip $PKG_ADDON_ID
    cd - &>/dev/null

    mkdir -p $ADDON_INSTALL_DIR
    cp $ADDON_BUILD/$PKG_ADDON_ID-$ADDONVER.zip $ADDON_INSTALL_DIR
    if [ -f $ADDON_BUILD/$PKG_ADDON_ID/changelog.txt ]; then
      cp $ADDON_BUILD/$PKG_ADDON_ID/changelog.txt $ADDON_INSTALL_DIR/changelog-$ADDONVER.txt
    fi
    if [ -f $ADDON_BUILD/$PKG_ADDON_ID/resources/icon.png ]; then
      mkdir -p $ADDON_INSTALL_DIR/resources
      cp $ADDON_BUILD/$PKG_ADDON_ID/resources/icon.png $ADDON_INSTALL_DIR/resources/icon.png
    fi

    # workaround for kodi pvr addons
    if [ -f $ADDON_BUILD/$PKG_ADDON_ID/icon.png ]; then
      cp $ADDON_BUILD/$PKG_ADDON_ID/icon.png $ADDON_INSTALL_DIR/icon.png
    fi

    if [ -f $ADDON_BUILD/$PKG_ADDON_ID/resources/fanart.png ]; then
      mkdir -p $ADDON_INSTALL_DIR/resources
      cp $ADDON_BUILD/$PKG_ADDON_ID/resources/fanart.png $ADDON_INSTALL_DIR/resources/fanart.png
    fi
    for f in $ADDON_BUILD/$PKG_ADDON_ID/resources/screenshot-*.{jpg,png}; do
      if [ -f "$f" ]; then
        mkdir -p $ADDON_INSTALL_DIR/resources
        cp $f $ADDON_INSTALL_DIR/resources
      fi
    done

    # Jenkins add-on build
    if [ "$ADDON_JENKINS" = "yes" ]; then
      ADDON_JENKINS_DIR="$TARGET_IMG/jenkins"
      ADDON_JENKINS_ADDON_NAME="$ADDON_VERSION-${DEVICE:-$PROJECT}-$TARGET_ARCH-$PKG_ADDON_ID-$ADDONVER"
      mkdir -p "$ADDON_JENKINS_DIR"
      cd $ADDON_INSTALL_DIR
      $TOOLCHAIN/bin/7za a -l -mx0 -bsp0 -bso0 -tzip $ADDON_JENKINS_DIR/$ADDON_JENKINS_ADDON_NAME.zip $PKG_ADDON_ID-$ADDONVER.zip resources/
      ( cd $ADDON_JENKINS_DIR
        sha256sum $ADDON_JENKINS_ADDON_NAME.zip > $ADDON_JENKINS_ADDON_NAME.zip.sha256
      )
      build_msg "CLR_INFO" "*** creating ${ADDON_JENKINS_ADDON_NAME}.zip for Jenkins complete ***"
    else
      build_msg "CLR_INFO" "*** creating  ${PKG_ADDON_ID} complete ***"
    fi
  fi
}

not_supported_arch() {
  build_msg "CLR_WARNING" "*** SKIP: ${PKG_ADDON_ID} '${TARGET_ARCH}' not supported ***"
  exit 0
}

not_supported_device() {
  build_msg "CLR_WARNING" "*** SKIP: ${PKG_ADDON_ID}: '${DEVICE:-${PROJECT}}' not supported ***"
  exit 0
}

# build addon function
build_addon() {
  # addon build
  . config/options $1

  # check support
  if [ -n "$PKG_ARCH" ]; then
    listcontains "$PKG_ARCH" "!$TARGET_ARCH" && not_supported_arch
    listcontains "$PKG_ARCH" "$TARGET_ARCH" || listcontains "$PKG_ARCH" "any" || not_supported_arch
  fi

  if [ -n "$PKG_ADDON_PROJECTS" ]; then
     [ "${DEVICE}" = "RPi" ] && _DEVICE="RPi1" || _DEVICE="${DEVICE}"

    if listcontains "$PKG_ADDON_PROJECTS" "!${_DEVICE:-$PROJECT}" ||
       listcontains "$PKG_ADDON_PROJECTS" "!${PROJECT}"; then
      not_supported_device
    fi

    if ! listcontains "$PKG_ADDON_PROJECTS" "${_DEVICE:-$PROJECT}" &&
       ! listcontains "$PKG_ADDON_PROJECTS" "${PROJECT}" &&
       ! listcontains "$PKG_ADDON_PROJECTS" "any"; then
      not_supported_device
    fi
  fi

  # build addon
  $SCRIPTS/build $1

  # cleanup old install path
  rm -rf $ADDON_BUILD

  # install addon parts
  if pkg_call_exists addon; then
    pkg_call addon
  else
    install_binary_addon $PKG_ADDON_ID
  fi

  # HACK for packages that provide multiple addons like screensavers.rsxs
  # addon's addon() in package.mk should take care for exporting
  # MULTI_ADDONS="addon.boo1 addon.boo2 addon.boo3"
  if [ -n "$MULTI_ADDONS" ] ; then
    for _ADDON in $MULTI_ADDONS ; do
      PKG_ADDON_ID=$_ADDON
      pack_addon
    done
  else
    pack_addon
  fi
}

# need parameter
if [ $# -eq 0 ]; then
  usage 1
fi

# collect list of addons for building
addons=""
addons_drop=""
show_only="false"
write_logs="no"
log_path="$BUILD/logs"
summary_file="/dev/null"
export BUILD_INDENT=$((${BUILD_INDENT:-1}+$BUILD_INDENT_SIZE))

# read addons from parameter list
while [ $# -gt 0 ]; do
  case $1 in
    --help)         usage 0;;
    --show-only)    show_only="true";;
    --write-logs=*) write_logs="${1:13}";;
    --log-path=*)   log_path="${1:11}";;
    --*)            usage 1;;
    -*)             addons_drop+=" $(find_addons ${1:1})";;
    *)              addons+=" $(find_addons $1)";;
  esac
  shift
done

# check log parameter
case "$write_logs" in
  no)     log_path=""
          remove_success_logs="false";;
  yes)    remove_success_logs="false";;
  errors) remove_success_logs="true";;
  *)      usage 1
esac
if [ -n "$log_path" ]; then
  mkdir -p "$log_path"
  summary_file="$log_path/addon-summary.log"
  rm -f $summary_file
fi

# check environment and create toolchain
$SCRIPTS/checkdeps
setup_toolchain target

# build addons, by calling function build_addon with one addon, after another
# (do not abort on build failure)
addons_failed=""
set +e
_count=''
for addon in $(tr " " "\n" <<< $addons | sort -u); do
  # no build, when addon is in drop list / should not build
  if listcontains "$addons_drop" "$addon"; then
    continue
  fi

  # show-only: print name and continue with next addon
  if [ "$show_only" = "true" ]; then
    echo $addon
    continue
  fi

  # define log file
  log_file=/dev/null
  if [ -n "$log_path" ]; then
    log_file="$log_path/$addon.log"
  fi

  # build package
  echo "$(print_color CLR_BUILD "CREATE ADDON $addon") (${DEVICE:-$PROJECT}/$TARGET_ARCH)" >&$SILENT_OUT
  _count+='x'
  ( build_addon $addon ) \
    2>&1 | tee $log_file
  if [ ${PIPESTATUS[0]} != 0 ]; then
    addons_failed+="$addon "
    echo "$(print_color CLR_ERROR "ADDON FAILED $addon")" >&$SILENT_OUT
    echo "failed: ${addon}" >> $summary_file
  else
    if [ "$remove_success_logs" = "true" ]; then
      rm -f $log_file
    fi
    echo "success: ${addon}" >> $summary_file
  fi
done

# show-only has no summary, can exit here
if [ "$show_only" = "true" ]; then
  exit 0
fi

# print summary
if [ "$_count" != 'x' ]; then
  if [ -z "$addons_failed" ]; then
    echo "$(print_color CLR_INFO "ALL ADDONS BUILDS SUCCESSFUL")"
    exit 0
  else
    die "$(print_color CLR_ERROR "FAILED ADDONS: $addons_failed")"
  fi
fi
